// Copyright (C) 2008 Taylor L. Riche <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

#include <sys/stat.h>
#include <fcntl.h>
#include "lc_short_lookup_op_Operator.h"
#include <boost/lexical_cast.hpp>
#include <hashlibpp.h>
#define BUFFER_SIZE 65536


void 
short_lookup_op::lookupWebContent(requestTypes::NetRequest * data, unsigned long dataSize)
{
  assert(data != NULL);

  int rd;
  struct stat sb;
  int res=0;
  socket_t dataSock = data->getSocketID();
        
  std::string root= "/home/riche/src/applications/benchmarks/attack/appdata/";
  std::string file = data->getFileName();
  std::string content="text/plain";

  file = root + file;

  //std::cout << "\n\n" << file << std::endl;

  res = stat(file.c_str(), &sb);
  int file_size = sb.st_size;

  if (res < 0) {
    std::string msg1 = "HTTP/1.1 404 File not found\r\n";
//     char msg[128];
    std::string msg;
    msg.append(msg1);
    msg.append("Content-Type: ");
    msg.append(content);
    msg.append("\r\nServer: lagniappe \r\nContent-Length: ");
    msg.append(boost::lexical_cast<std::string>(msg1.length()));
    msg.append("\r\n\r\n");
    char *bad_buffer = new char[msg.length()];

    strcpy(bad_buffer, msg.c_str());

    requestTypes::NetRequest *out_data = new requestTypes::NetRequest(bad_buffer,strlen(bad_buffer),data->getSocketID());
    assert(out_data != NULL);
    out(out_data, sizeof(requestTypes::NetRequest));
  }
  else {
    int ix=0;
    int header_len;
	  
    char hdrs[BUFFER_SIZE];
    if (data->getClose()) {
      sprintf(hdrs, "HTTP/1.1 200 OK\r\nContent-type: %s\r\nServer: Lagniappe 0.1\r\nConnection: close\r\nContent-Length: %d\r\n\r\n",
	      content.c_str(), file_size);
    }
    else {
      sprintf(hdrs, "HTTP/1.1 200 OK\r\nContent-type: %s\r\nServer: Lagniappe 0.1\r\nContent-Length: %d\r\n\r\n",
	      content.c_str(), file_size);
    }
    header_len = strlen(hdrs);
	  
    int fd = open(file.c_str(), O_RDONLY);
    if (fd < 0) {
      perror("Reading");
      //closeSocket(in->socket);
      return ;
    }
	  
    char read_data[BUFFER_SIZE];
    std::string read_string = "";
    state_records::FileRecord_p record;
    if(!fileLockMap[getFlowID(data)]) {
      state_records::FileRecord_p tr(new state_records::FileRecord(getNewMutex()));
      record = fileLockMap[getFlowID(data)] = tr;
    }
    else {
      record = fileLockMap[getFlowID(data)];
    }
    // take lock
    record->openFile();
    
    // readFile data

    do{
	    
      if ((rd = read(fd, read_data, BUFFER_SIZE)) < 0) {
	perror("read");
	//closeSocket(in->socket);
	return ;
      }
      //strcat(new_buffer+header_len+ix,hdrs);
            
      ix += rd;
      read_string.append(read_data);
    } while (ix < sb.st_size);
    close(fd);
    // fake doing work based on session id
//     for(int i = 0; i < dataSock * 100; ++i) {
//       if(i < 300) {ix = i;}
//     }
    // release lock


    sha512wrapper hasher;
    for(int i = 0; i < 1; i++) {
    std::string hash = hasher.getHashFromString(read_string);
    if(record->getHash() != hash) {
      record->setHash(hash);
    }
    }
    
    record->closeFile();

    char *new_buffer = new char[header_len + strlen(read_string.c_str())];
    strcpy(new_buffer, hdrs);
    strcat(new_buffer, read_string.c_str());
    requestTypes::NetRequest *out_data = new requestTypes::NetRequest(new_buffer,strlen(new_buffer), dataSock);
    assert(out_data != NULL);
    assert(dataSock >= 0);
    assert(ix > 5);
    assert(out_data->getSocketID()>= 0);
    out(out_data, sizeof(requestTypes::NetRequest));
  }
  if(!inProf) delete data;

  return;
}


requestTypes::NetRequest *
short_lookup_op::geninRequest()
{
  return new requestTypes::NetRequest(NULL,0,5,"index0.html");
}


void
short_lookup_op::my_install(void * data)
{
}

void *
short_lookup_op::my_get()
{
  return NULL;
}

void
short_lookup_op::my_purge(void * data)
{
}

void
short_lookup_op::my_init()
{
}
